<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="tong.li&#39;s blog">
  <meta name="keyword" content="彤哥哥博客，95后技术爱好者,现就职于同程旅行/同程艺龙上海分公司，专注于互联网技术分享的平台。">
  
    <link rel="shortcut icon" href="/css/images/icon.png">
  
  <title>
    
      【Java并发编程实战】线程池应用之Executors线程池静态工厂 | 彤哥哥的博客
    
  </title>
  <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/highlight.js/9.12.0/styles/tomorrow-night.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
  <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="https://cdn.staticfile.org/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


  
  
    
<script src="/js/local-search.js"></script>


<meta name="generator" content="Hexo 5.4.2"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>彤哥哥的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/series/" class="item-link">分类</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">项目</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于</a>
          
        </li>
      
      
        <li class="menu-item menu-item-search right-list">
    <a role="button" class="popup-trigger">
        <i class="fa fa-search fa-fw"></i>
    </a>
</li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/series/" class="menu-link">分类</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">项目</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于</a>
            
          </li>
        
      </ul>
    </div>
    
      <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
            <span class="search-icon">
                <i class="fa fa-search"></i>
            </span>
            <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off"
                    placeholder="Please enter your keyword(s) to search." spellcheck="false"
                    type="search" class="search-input">
            </div>
            <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>
    
  </div>
</header>

    <div id="article-banner">
  <h2>【Java并发编程实战】线程池应用之Executors线程池静态工厂</h2>
  <p class="post-date">2018-06-10</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><p>今天我们来认识一下，线程池的静态工厂Executors类，平时写测试代码的时候可用一用，生产代码尽量少用。为什么说生产上尽量少用呢？这是有原因的，请耐心听彤哥讲解。</p>
<p>阿里的代码规约不建议使用这样的工厂类，而建议使用手动创建并管理ThreadPoolExecutor，在阿里巴巴Java开发手册中，编程规约下的并发处理规约第4点如下：</p>
<blockquote>
<p>【强制】线程池不允许使用Executors去创建，而是通过ThreadPoolExecutor的方式，这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。<br>说明：Executors返回的线程池对象的弊端如下：</p>
<p> 1）<code>FixedThreadPool</code>和<code>SingleThreadPool</code>: 允许的请求队列长度为Integer.MAX_VALUE，可能会堆积大量的请求，从而导致OOM。</p>
<p> 2）<code>CachedThreadPool</code>和<code>ScheduledThreadPool</code>: 允许的创建线程数量为Integer.MAX_VALUE，可能会创建大量的线程，从而导致OOM。</p>
<p>正例 1：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//org.apache.commons.lang3.concurrent.BasicThreadFactory</span></span><br><span class="line"><span class="type">ScheduledExecutorService</span> <span class="variable">executorService</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ScheduledThreadPoolExecutor</span>(<span class="number">1</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">BasicThreadFactory</span>.Builder().namingPattern(<span class="string">&quot;example-schedule-pool-%d&quot;</span>).daemon(<span class="literal">true</span>).build());</span><br></pre></td></tr></table></figure>


<p>正例 2：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ThreadFactory</span> <span class="variable">namedThreadFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadFactoryBuilder</span>()</span><br><span class="line">  .setNameFormat(<span class="string">&quot;demo-pool-%d&quot;</span>).build();</span><br><span class="line"><span class="comment">//Common Thread Pool</span></span><br><span class="line"><span class="type">ExecutorService</span> <span class="variable">pool</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">5</span>, <span class="number">200</span>,</span><br><span class="line">                                              <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                                              <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;(<span class="number">1024</span>), namedThreadFactory, <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.AbortPolicy());</span><br><span class="line">pool.execute(()-&gt; System.out.println(Thread.currentThread().getName()));</span><br><span class="line">pool.shutdown();<span class="comment">//gracefully shutdown        </span></span><br></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">正例 3：</span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userThreadPool&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;corePoolSize&quot;</span> <span class="attr">value</span>=<span class="string">&quot;10&quot;</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;maxPoolSize&quot;</span> <span class="attr">value</span>=<span class="string">&quot;100&quot;</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;queueCapacity&quot;</span> <span class="attr">value</span>=<span class="string">&quot;2000&quot;</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;threadFactory&quot;</span> <span class="attr">value</span>= <span class="string">threadFactory</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;rejectedExecutionHandler&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">ref</span> <span class="attr">local</span>=<span class="string">&quot;rejectedExecutionHandler&quot;</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">//in code</span><br><span class="line">userThreadPool.execute(thread);</span><br></pre></td></tr></table></figure>
</blockquote>
<p>看到如下的规约，我们是不是没必要往下学了？答案是当然不行的，我们虽然不怎么用，但是研究其源码，可以让我们更深入线程池原理（增强内力），使得我们以后更容易设计线程池并能够高效管理线程，以至于不像代码规约描述的那样：用而不当导致OOM的问题。</p>
<h2 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h2><p>好了，话不多说，直接上菜(源码)，够我们今天喝几壶了，哈哈。。。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.util.concurrent;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicInteger;</span><br><span class="line"><span class="keyword">import</span> java.security.AccessControlContext;</span><br><span class="line"><span class="keyword">import</span> java.security.AccessController;</span><br><span class="line"><span class="keyword">import</span> java.security.PrivilegedAction;</span><br><span class="line"><span class="keyword">import</span> java.security.PrivilegedExceptionAction;</span><br><span class="line"><span class="keyword">import</span> java.security.PrivilegedActionException;</span><br><span class="line"><span class="keyword">import</span> java.security.AccessControlException;</span><br><span class="line"><span class="keyword">import</span> sun.security.util.SecurityConstants;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Executors线程池静态工厂类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Executors</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建重用固定数量线程的线程池,使用的是共享无参无边界队列。</span></span><br><span class="line"><span class="comment">     * 在任何时候，最多线程将是活动的处理任务。</span></span><br><span class="line"><span class="comment">     * 如果在所有线程都处于活动状态时提交了其他任务，它们将在队列中等待，直到线程可用。</span></span><br><span class="line"><span class="comment">     * 在关闭之前，如果任何线程在执行期间因失败而终止,如果需要，将更换一个新的，执行后续任务。</span></span><br><span class="line"><span class="comment">     * 池中的线程将存在直到它显式executerservice关闭。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newFixedThreadPool</span><span class="params">(<span class="type">int</span> nThreads)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(nThreads, nThreads,</span><br><span class="line">                                      <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                                      <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 该方法是JDk8提供的。特殊的线程池，采用JDK1.7的ForkJoinPool实现</span></span><br><span class="line"><span class="comment">     * 创建一个线程池，以维护足够的线程来支持给定的并行级别，并且可以使用多个队列来减少争用。</span></span><br><span class="line"><span class="comment">     * 平行度级别对应于主动参与或可用于的线程的最大数目从事，任务处理。</span></span><br><span class="line"><span class="comment">     * 实际线程数可能动态增长和收缩。偷工减料是不行的，保证提交任务的顺序执行。</span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> 并行级别</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newWorkStealingPool</span><span class="params">(<span class="type">int</span> parallelism)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ForkJoinPool</span></span><br><span class="line">            (parallelism,</span><br><span class="line">             ForkJoinPool.defaultForkJoinWorkerThreadFactory,</span><br><span class="line">             <span class="literal">null</span>, <span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 只是默认参数用的是当前机器可利用CPU核数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newWorkStealingPool</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ForkJoinPool</span></span><br><span class="line">            (Runtime.getRuntime().availableProcessors(),</span><br><span class="line">             ForkJoinPool.defaultForkJoinWorkerThreadFactory,</span><br><span class="line">             <span class="literal">null</span>, <span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 创建重用固定数量线程的线程池</span></span><br><span class="line"><span class="comment">     * 只不过参数多了一个，可以自定义线程池工厂</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newFixedThreadPool</span><span class="params">(<span class="type">int</span> nThreads, ThreadFactory threadFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(nThreads, nThreads,</span><br><span class="line">                                      <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                                      <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;(),</span><br><span class="line">                                      threadFactory);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建使用单个工作线程操作的执行器，即单线程工作模式，不可配置线程的大小。</span></span><br><span class="line"><span class="comment">     * 也是在一个无边界的队列中运行的。相当于newFixedThreadPool(1)，</span></span><br><span class="line"><span class="comment">     * 在任何时刻，当前线程池只有1个活动线程，不可能出现其他的工作线程。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newSingleThreadExecutor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">FinalizableDelegatedExecutorService</span></span><br><span class="line">            (<span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">1</span>, <span class="number">1</span>,</span><br><span class="line">                                    <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                                    <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;()));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 创建使用单个工作线程操作的执行器，即单线程工作模式，不可配置线程的大小。</span></span><br><span class="line"><span class="comment">     * 只不过可以自定义线程池工厂</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newSingleThreadExecutor</span><span class="params">(ThreadFactory threadFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">FinalizableDelegatedExecutorService</span></span><br><span class="line">            (<span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">1</span>, <span class="number">1</span>,</span><br><span class="line">                                    <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                                    <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;(),</span><br><span class="line">                                    threadFactory));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建一个可重用的线程池: 根据需要创建新线程，但将重用以前构造的线程可用。</span></span><br><span class="line"><span class="comment">     * 执行许多短期异步任务的程序，使用这类线程池可以提升程序性能。</span></span><br><span class="line"><span class="comment">     * 如果没有线程可用，则线程被创建并添加到池中。</span></span><br><span class="line"><span class="comment">     * 具有60秒未使用的线程，线程池则回收该线程。</span></span><br><span class="line"><span class="comment">     * 如果线程可用，则重用之前的活动线程。</span></span><br><span class="line"><span class="comment">     * 如果使用不当可能导致OOM。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newCachedThreadPool</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">0</span>, Integer.MAX_VALUE,</span><br><span class="line">                                      <span class="number">60L</span>, TimeUnit.SECONDS,</span><br><span class="line">                                      <span class="keyword">new</span> <span class="title class_">SynchronousQueue</span>&lt;Runnable&gt;());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 创建一个可重用的线程池</span></span><br><span class="line"><span class="comment">     * 只不过可以自定义线程池工厂</span></span><br><span class="line"><span class="comment">     * 如果使用不当可能导致OOM。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newCachedThreadPool</span><span class="params">(ThreadFactory threadFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">0</span>, Integer.MAX_VALUE,</span><br><span class="line">                                      <span class="number">60L</span>, TimeUnit.SECONDS,</span><br><span class="line">                                      <span class="keyword">new</span> <span class="title class_">SynchronousQueue</span>&lt;Runnable&gt;(),</span><br><span class="line">                                      threadFactory);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 创建一个单线程的延迟任务线程池，可代替Timer(使用繁琐，线程不安全类)，</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ScheduledExecutorService <span class="title function_">newSingleThreadScheduledExecutor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DelegatedScheduledExecutorService</span></span><br><span class="line">            (<span class="keyword">new</span> <span class="title class_">ScheduledThreadPoolExecutor</span>(<span class="number">1</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 创建一个单线程的延迟任务线程池，可代替Timer(使用繁琐，线程不安全类)，</span></span><br><span class="line"><span class="comment">     * 只不过可以自定义线程池工厂</span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ScheduledExecutorService <span class="title function_">newSingleThreadScheduledExecutor</span><span class="params">(ThreadFactory threadFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DelegatedScheduledExecutorService</span></span><br><span class="line">            (<span class="keyword">new</span> <span class="title class_">ScheduledThreadPoolExecutor</span>(<span class="number">1</span>, threadFactory));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">     <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 创建一个延迟任务线程池</span></span><br><span class="line"><span class="comment">     * 只不过可以自定义线程池核心大小</span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ScheduledExecutorService <span class="title function_">newScheduledThreadPool</span><span class="params">(<span class="type">int</span> corePoolSize)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ScheduledThreadPoolExecutor</span>(corePoolSize);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重载方法: 创建一个延迟任务线程池</span></span><br><span class="line"><span class="comment">     * 只不过可以自定义线程池核心大小和最大线程数量</span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ScheduledExecutorService <span class="title function_">newScheduledThreadPool</span><span class="params">(</span></span><br><span class="line"><span class="params">            <span class="type">int</span> corePoolSize, ThreadFactory threadFactory)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ScheduledThreadPoolExecutor</span>(corePoolSize, threadFactory);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns an object that delegates all defined &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * ExecutorService&#125; methods to the given executor, but not any</span></span><br><span class="line"><span class="comment">     * other methods that might otherwise be accessible using</span></span><br><span class="line"><span class="comment">     * casts. This provides a way to safely &quot;freeze&quot; configuration and</span></span><br><span class="line"><span class="comment">     * disallow tuning of a given concrete implementation.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> executor the underlying implementation</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> an &#123;<span class="doctag">@code</span> ExecutorService&#125; instance</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if executor null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">unconfigurableExecutorService</span><span class="params">(ExecutorService executor)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (executor == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DelegatedExecutorService</span>(executor);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns an object that delegates all defined &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * ScheduledExecutorService&#125; methods to the given executor, but</span></span><br><span class="line"><span class="comment">     * not any other methods that might otherwise be accessible using</span></span><br><span class="line"><span class="comment">     * casts. This provides a way to safely &quot;freeze&quot; configuration and</span></span><br><span class="line"><span class="comment">     * disallow tuning of a given concrete implementation.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> executor the underlying implementation</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a &#123;<span class="doctag">@code</span> ScheduledExecutorService&#125; instance</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if executor null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ScheduledExecutorService <span class="title function_">unconfigurableScheduledExecutorService</span><span class="params">(ScheduledExecutorService executor)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (executor == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DelegatedScheduledExecutorService</span>(executor);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a default thread factory used to create new threads.</span></span><br><span class="line"><span class="comment">     * This factory creates all new threads used by an Executor in the</span></span><br><span class="line"><span class="comment">     * same &#123;<span class="doctag">@link</span> ThreadGroup&#125;. If there is a &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * java.lang.SecurityManager&#125;, it uses the group of &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * System#getSecurityManager&#125;, else the group of the thread</span></span><br><span class="line"><span class="comment">     * invoking this &#123;<span class="doctag">@code</span> defaultThreadFactory&#125; method. Each new</span></span><br><span class="line"><span class="comment">     * thread is created as a non-daemon thread with priority set to</span></span><br><span class="line"><span class="comment">     * the smaller of &#123;<span class="doctag">@code</span> Thread.NORM_PRIORITY&#125; and the maximum</span></span><br><span class="line"><span class="comment">     * priority permitted in the thread group.  New threads have names</span></span><br><span class="line"><span class="comment">     * accessible via &#123;<span class="doctag">@link</span> Thread#getName&#125; of</span></span><br><span class="line"><span class="comment">     * &lt;em&gt;pool-N-thread-M&lt;/em&gt;, where &lt;em&gt;N&lt;/em&gt; is the sequence</span></span><br><span class="line"><span class="comment">     * number of this factory, and &lt;em&gt;M&lt;/em&gt; is the sequence number</span></span><br><span class="line"><span class="comment">     * of the thread created by this factory.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a thread factory</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ThreadFactory <span class="title function_">defaultThreadFactory</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DefaultThreadFactory</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a thread factory used to create new threads that</span></span><br><span class="line"><span class="comment">     * have the same permissions as the current thread.</span></span><br><span class="line"><span class="comment">     * This factory creates threads with the same settings as &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * Executors#defaultThreadFactory&#125;, additionally setting the</span></span><br><span class="line"><span class="comment">     * AccessControlContext and contextClassLoader of new threads to</span></span><br><span class="line"><span class="comment">     * be the same as the thread invoking this</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@code</span> privilegedThreadFactory&#125; method.  A new</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@code</span> privilegedThreadFactory&#125; can be created within an</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@link</span> AccessController#doPrivileged AccessController.doPrivileged&#125;</span></span><br><span class="line"><span class="comment">     * action setting the current thread&#x27;s access control context to</span></span><br><span class="line"><span class="comment">     * create threads with the selected permission settings holding</span></span><br><span class="line"><span class="comment">     * within that action.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * &lt;p&gt;Note that while tasks running within such threads will have</span></span><br><span class="line"><span class="comment">     * the same access control and class loader settings as the</span></span><br><span class="line"><span class="comment">     * current thread, they need not have the same &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * java.lang.ThreadLocal&#125; or &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * java.lang.InheritableThreadLocal&#125; values. If necessary,</span></span><br><span class="line"><span class="comment">     * particular values of thread locals can be set or reset before</span></span><br><span class="line"><span class="comment">     * any task runs in &#123;<span class="doctag">@link</span> ThreadPoolExecutor&#125; subclasses using</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@link</span> ThreadPoolExecutor#beforeExecute(Thread, Runnable)&#125;.</span></span><br><span class="line"><span class="comment">     * Also, if it is necessary to initialize worker threads to have</span></span><br><span class="line"><span class="comment">     * the same InheritableThreadLocal settings as some other</span></span><br><span class="line"><span class="comment">     * designated thread, you can create a custom ThreadFactory in</span></span><br><span class="line"><span class="comment">     * which that thread waits for and services requests to create</span></span><br><span class="line"><span class="comment">     * others that will inherit its values.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a thread factory</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> AccessControlException if the current access control</span></span><br><span class="line"><span class="comment">     * context does not have permission to both get and set context</span></span><br><span class="line"><span class="comment">     * class loader</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ThreadFactory <span class="title function_">privilegedThreadFactory</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PrivilegedThreadFactory</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a &#123;<span class="doctag">@link</span> Callable&#125; object that, when</span></span><br><span class="line"><span class="comment">     * called, runs the given task and returns the given result.  This</span></span><br><span class="line"><span class="comment">     * can be useful when applying methods requiring a</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@code</span> Callable&#125; to an otherwise resultless action.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> task the task to run</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> result the result to return</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> &lt;T&gt; the type of the result</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a callable object</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if task null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; Callable&lt;T&gt; <span class="title function_">callable</span><span class="params">(Runnable task, T result)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (task == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RunnableAdapter</span>&lt;T&gt;(task, result);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a &#123;<span class="doctag">@link</span> Callable&#125; object that, when</span></span><br><span class="line"><span class="comment">     * called, runs the given task and returns &#123;<span class="doctag">@code</span> null&#125;.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> task the task to run</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a callable object</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if task null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Callable&lt;Object&gt; <span class="title function_">callable</span><span class="params">(Runnable task)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (task == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RunnableAdapter</span>&lt;Object&gt;(task, <span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a &#123;<span class="doctag">@link</span> Callable&#125; object that, when</span></span><br><span class="line"><span class="comment">     * called, runs the given privileged action and returns its result.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> action the privileged action to run</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a callable object</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if action null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Callable&lt;Object&gt; <span class="title function_">callable</span><span class="params">(<span class="keyword">final</span> PrivilegedAction&lt;?&gt; action)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (action == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Callable</span>&lt;Object&gt;() &#123;</span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">call</span><span class="params">()</span> &#123; <span class="keyword">return</span> action.run(); &#125;&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a &#123;<span class="doctag">@link</span> Callable&#125; object that, when</span></span><br><span class="line"><span class="comment">     * called, runs the given privileged exception action and returns</span></span><br><span class="line"><span class="comment">     * its result.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> action the privileged exception action to run</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a callable object</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if action null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Callable&lt;Object&gt; <span class="title function_">callable</span><span class="params">(<span class="keyword">final</span> PrivilegedExceptionAction&lt;?&gt; action)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (action == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Callable</span>&lt;Object&gt;() &#123;</span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123; <span class="keyword">return</span> action.run(); &#125;&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a &#123;<span class="doctag">@link</span> Callable&#125; object that will, when called,</span></span><br><span class="line"><span class="comment">     * execute the given &#123;<span class="doctag">@code</span> callable&#125; under the current access</span></span><br><span class="line"><span class="comment">     * control context. This method should normally be invoked within</span></span><br><span class="line"><span class="comment">     * an &#123;<span class="doctag">@link</span> AccessController#doPrivileged AccessController.doPrivileged&#125;</span></span><br><span class="line"><span class="comment">     * action to create callables that will, if possible, execute</span></span><br><span class="line"><span class="comment">     * under the selected permission settings holding within that</span></span><br><span class="line"><span class="comment">     * action; or if not possible, throw an associated &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment">     * AccessControlException&#125;.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> callable the underlying task</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> &lt;T&gt; the type of the callable&#x27;s result</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> a callable object</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if callable null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; Callable&lt;T&gt; <span class="title function_">privilegedCallable</span><span class="params">(Callable&lt;T&gt; callable)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (callable == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PrivilegedCallable</span>&lt;T&gt;(callable);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; Callable&lt;T&gt; <span class="title function_">privilegedCallableUsingCurrentClassLoader</span><span class="params">(Callable&lt;T&gt; callable)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (callable == <span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PrivilegedCallableUsingCurrentClassLoader</span>&lt;T&gt;(callable);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Non-public classes supporting the public methods</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 运行给定任务并返回给定结果的可调用文件</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">RunnableAdapter</span>&lt;T&gt; <span class="keyword">implements</span> <span class="title class_">Callable</span>&lt;T&gt; &#123;</span><br><span class="line">        <span class="keyword">final</span> Runnable task;</span><br><span class="line">        <span class="keyword">final</span> T result;</span><br><span class="line">        RunnableAdapter(Runnable task, T result) &#123;</span><br><span class="line">            <span class="built_in">this</span>.task = task;</span><br><span class="line">            <span class="built_in">this</span>.result = result;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> T <span class="title function_">call</span><span class="params">()</span> &#123;</span><br><span class="line">            task.run();</span><br><span class="line">            <span class="keyword">return</span> result;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 在已建立的访问控制设置下运行的可调用文件</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">PrivilegedCallable</span>&lt;T&gt; <span class="keyword">implements</span> <span class="title class_">Callable</span>&lt;T&gt; &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Callable&lt;T&gt; task;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> AccessControlContext acc;</span><br><span class="line"></span><br><span class="line">        PrivilegedCallable(Callable&lt;T&gt; task) &#123;</span><br><span class="line">            <span class="built_in">this</span>.task = task;</span><br><span class="line">            <span class="built_in">this</span>.acc = AccessController.getContext();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> T <span class="title function_">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> AccessController.doPrivileged(</span><br><span class="line">                    <span class="keyword">new</span> <span class="title class_">PrivilegedExceptionAction</span>&lt;T&gt;() &#123;</span><br><span class="line">                        <span class="keyword">public</span> T <span class="title function_">run</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">                            <span class="keyword">return</span> task.call();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;, acc);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (PrivilegedActionException e) &#123;</span><br><span class="line">                <span class="keyword">throw</span> e.getException();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 在已建立的访问控制设置和当前类加载器下运行的可调用文件。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">PrivilegedCallableUsingCurrentClassLoader</span>&lt;T&gt; <span class="keyword">implements</span> <span class="title class_">Callable</span>&lt;T&gt; &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Callable&lt;T&gt; task;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> AccessControlContext acc;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> ClassLoader ccl;</span><br><span class="line"></span><br><span class="line">        PrivilegedCallableUsingCurrentClassLoader(Callable&lt;T&gt; task) &#123;</span><br><span class="line">            <span class="type">SecurityManager</span> <span class="variable">sm</span> <span class="operator">=</span> System.getSecurityManager();</span><br><span class="line">            <span class="keyword">if</span> (sm != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// Calls to getContextClassLoader from this class</span></span><br><span class="line">                <span class="comment">// never trigger a security check, but we check</span></span><br><span class="line">                <span class="comment">// whether our callers have this permission anyways.</span></span><br><span class="line">                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// Whether setContextClassLoader turns out to be necessary</span></span><br><span class="line">                <span class="comment">// or not, we fail fast if permission is not available.</span></span><br><span class="line">                sm.checkPermission(<span class="keyword">new</span> <span class="title class_">RuntimePermission</span>(<span class="string">&quot;setContextClassLoader&quot;</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="built_in">this</span>.task = task;</span><br><span class="line">            <span class="built_in">this</span>.acc = AccessController.getContext();</span><br><span class="line">            <span class="built_in">this</span>.ccl = Thread.currentThread().getContextClassLoader();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> T <span class="title function_">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> AccessController.doPrivileged(</span><br><span class="line">                    <span class="keyword">new</span> <span class="title class_">PrivilegedExceptionAction</span>&lt;T&gt;() &#123;</span><br><span class="line">                        <span class="keyword">public</span> T <span class="title function_">run</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">                            <span class="type">Thread</span> <span class="variable">t</span> <span class="operator">=</span> Thread.currentThread();</span><br><span class="line">                            <span class="type">ClassLoader</span> <span class="variable">cl</span> <span class="operator">=</span> t.getContextClassLoader();</span><br><span class="line">                            <span class="keyword">if</span> (ccl == cl) &#123;</span><br><span class="line">                                <span class="keyword">return</span> task.call();</span><br><span class="line">                            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                                t.setContextClassLoader(ccl);</span><br><span class="line">                                <span class="keyword">try</span> &#123;</span><br><span class="line">                                    <span class="keyword">return</span> task.call();</span><br><span class="line">                                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                                    t.setContextClassLoader(cl);</span><br><span class="line">                                &#125;</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;, acc);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (PrivilegedActionException e) &#123;</span><br><span class="line">                <span class="keyword">throw</span> e.getException();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 默认线程工厂</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">DefaultThreadFactory</span> <span class="keyword">implements</span> <span class="title class_">ThreadFactory</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">AtomicInteger</span> <span class="variable">poolNumber</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AtomicInteger</span>(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> ThreadGroup group;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">AtomicInteger</span> <span class="variable">threadNumber</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AtomicInteger</span>(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> String namePrefix;</span><br><span class="line"></span><br><span class="line">        DefaultThreadFactory() &#123;</span><br><span class="line">            <span class="type">SecurityManager</span> <span class="variable">s</span> <span class="operator">=</span> System.getSecurityManager();</span><br><span class="line">            group = (s != <span class="literal">null</span>) ? s.getThreadGroup() :</span><br><span class="line">                                  Thread.currentThread().getThreadGroup();</span><br><span class="line">            namePrefix = <span class="string">&quot;pool-&quot;</span> +</span><br><span class="line">                          poolNumber.getAndIncrement() +</span><br><span class="line">                         <span class="string">&quot;-thread-&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Thread <span class="title function_">newThread</span><span class="params">(Runnable r)</span> &#123;</span><br><span class="line">            <span class="type">Thread</span> <span class="variable">t</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(group, r,</span><br><span class="line">                                  namePrefix + threadNumber.getAndIncrement(),</span><br><span class="line">                                  <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">if</span> (t.isDaemon())</span><br><span class="line">                t.setDaemon(<span class="literal">false</span>);</span><br><span class="line">            <span class="keyword">if</span> (t.getPriority() != Thread.NORM_PRIORITY)</span><br><span class="line">                t.setPriority(Thread.NORM_PRIORITY);</span><br><span class="line">            <span class="keyword">return</span> t;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 线程工厂捕获访问控制上下文和类加载器</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">PrivilegedThreadFactory</span> <span class="keyword">extends</span> <span class="title class_">DefaultThreadFactory</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> AccessControlContext acc;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> ClassLoader ccl;</span><br><span class="line"></span><br><span class="line">        PrivilegedThreadFactory() &#123;</span><br><span class="line">            <span class="built_in">super</span>();</span><br><span class="line">            <span class="type">SecurityManager</span> <span class="variable">sm</span> <span class="operator">=</span> System.getSecurityManager();</span><br><span class="line">            <span class="keyword">if</span> (sm != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// Calls to getContextClassLoader from this class</span></span><br><span class="line">                <span class="comment">// never trigger a security check, but we check</span></span><br><span class="line">                <span class="comment">// whether our callers have this permission anyways.</span></span><br><span class="line">                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// Fail fast</span></span><br><span class="line">                sm.checkPermission(<span class="keyword">new</span> <span class="title class_">RuntimePermission</span>(<span class="string">&quot;setContextClassLoader&quot;</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="built_in">this</span>.acc = AccessController.getContext();</span><br><span class="line">            <span class="built_in">this</span>.ccl = Thread.currentThread().getContextClassLoader();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Thread <span class="title function_">newThread</span><span class="params">(<span class="keyword">final</span> Runnable r)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">super</span>.newThread(<span class="keyword">new</span> <span class="title class_">Runnable</span>() &#123;</span><br><span class="line">                <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">                    AccessController.doPrivileged(<span class="keyword">new</span> <span class="title class_">PrivilegedAction</span>&lt;Void&gt;() &#123;</span><br><span class="line">                        <span class="keyword">public</span> Void <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">                            Thread.currentThread().setContextClassLoader(ccl);</span><br><span class="line">                            r.run();</span><br><span class="line">                            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;, acc);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 仅公开ExecutorService方法的包装类</span></span><br><span class="line"><span class="comment">     * 执行器服务的实现类</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">DelegatedExecutorService</span> <span class="keyword">extends</span> <span class="title class_">AbstractExecutorService</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> ExecutorService e;</span><br><span class="line">        DelegatedExecutorService(ExecutorService executor) &#123; e = executor; &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">(Runnable command)</span> &#123; e.execute(command); &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">shutdown</span><span class="params">()</span> &#123; e.shutdown(); &#125;</span><br><span class="line">        <span class="keyword">public</span> List&lt;Runnable&gt; <span class="title function_">shutdownNow</span><span class="params">()</span> &#123; <span class="keyword">return</span> e.shutdownNow(); &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isShutdown</span><span class="params">()</span> &#123; <span class="keyword">return</span> e.isShutdown(); &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isTerminated</span><span class="params">()</span> &#123; <span class="keyword">return</span> e.isTerminated(); &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">awaitTermination</span><span class="params">(<span class="type">long</span> timeout, TimeUnit unit)</span></span><br><span class="line">            <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">            <span class="keyword">return</span> e.awaitTermination(timeout, unit);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> Future&lt;?&gt; submit(Runnable task) &#123;</span><br><span class="line">            <span class="keyword">return</span> e.submit(task);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;T&gt; Future&lt;T&gt; <span class="title function_">submit</span><span class="params">(Callable&lt;T&gt; task)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> e.submit(task);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;T&gt; Future&lt;T&gt; <span class="title function_">submit</span><span class="params">(Runnable task, T result)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> e.submit(task, result);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;T&gt; List&lt;Future&lt;T&gt;&gt; <span class="title function_">invokeAll</span><span class="params">(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks)</span></span><br><span class="line">            <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">            <span class="keyword">return</span> e.invokeAll(tasks);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;T&gt; List&lt;Future&lt;T&gt;&gt; <span class="title function_">invokeAll</span><span class="params">(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks,</span></span><br><span class="line"><span class="params">                                             <span class="type">long</span> timeout, TimeUnit unit)</span></span><br><span class="line">            <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">            <span class="keyword">return</span> e.invokeAll(tasks, timeout, unit);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;T&gt; T <span class="title function_">invokeAny</span><span class="params">(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks)</span></span><br><span class="line">            <span class="keyword">throws</span> InterruptedException, ExecutionException &#123;</span><br><span class="line">            <span class="keyword">return</span> e.invokeAny(tasks);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;T&gt; T <span class="title function_">invokeAny</span><span class="params">(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks,</span></span><br><span class="line"><span class="params">                               <span class="type">long</span> timeout, TimeUnit unit)</span></span><br><span class="line">            <span class="keyword">throws</span> InterruptedException, ExecutionException, TimeoutException &#123;</span><br><span class="line">            <span class="keyword">return</span> e.invokeAny(tasks, timeout, unit);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">FinalizableDelegatedExecutorService</span></span><br><span class="line">        <span class="keyword">extends</span> <span class="title class_">DelegatedExecutorService</span> &#123;</span><br><span class="line">        FinalizableDelegatedExecutorService(ExecutorService executor) &#123;</span><br><span class="line">            <span class="built_in">super</span>(executor);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">finalize</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="built_in">super</span>.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 仅公开ScheduledExecutorService的包装类</span></span><br><span class="line"><span class="comment">     * ScheduledExecutorService实现的方法</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">DelegatedScheduledExecutorService</span></span><br><span class="line">            <span class="keyword">extends</span> <span class="title class_">DelegatedExecutorService</span></span><br><span class="line">            <span class="keyword">implements</span> <span class="title class_">ScheduledExecutorService</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> ScheduledExecutorService e;</span><br><span class="line">        DelegatedScheduledExecutorService(ScheduledExecutorService executor) &#123;</span><br><span class="line">            <span class="built_in">super</span>(executor);</span><br><span class="line">            e = executor;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> ScheduledFuture&lt;?&gt; schedule(Runnable command, <span class="type">long</span> delay, TimeUnit unit) &#123;</span><br><span class="line">            <span class="keyword">return</span> e.schedule(command, delay, unit);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> &lt;V&gt; ScheduledFuture&lt;V&gt; <span class="title function_">schedule</span><span class="params">(Callable&lt;V&gt; callable, <span class="type">long</span> delay, TimeUnit unit)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> e.schedule(callable, delay, unit);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> ScheduledFuture&lt;?&gt; scheduleAtFixedRate(Runnable command, <span class="type">long</span> initialDelay, <span class="type">long</span> period, TimeUnit unit) &#123;</span><br><span class="line">            <span class="keyword">return</span> e.scheduleAtFixedRate(command, initialDelay, period, unit);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> ScheduledFuture&lt;?&gt; scheduleWithFixedDelay(Runnable command, <span class="type">long</span> initialDelay, <span class="type">long</span> delay, TimeUnit unit) &#123;</span><br><span class="line">            <span class="keyword">return</span> e.scheduleWithFixedDelay(command, initialDelay, delay, unit);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 不允许实例化 */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Executors</span><span class="params">()</span> &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="常用方法"><a href="#常用方法" class="headerlink" title="常用方法"></a>常用方法</h2><h3 id="FixedThreadPool"><a href="#FixedThreadPool" class="headerlink" title="FixedThreadPool"></a>FixedThreadPool</h3><p>FixedThreadPool，可重用固定线程数的线程池。</p>
<p>corePoolSize 和 maximumPoolSize都设置为创建FixedThreadPool时指定的参数nThreads，意味着当线程池满时且阻塞队列也已经满时，如果继续提交任务，则会直接走拒绝策略，该线程池不会再新建线程来执行任务，而是直接走拒绝策略。FixedThreadPool使用的是默认的拒绝策略，即AbortPolicy，则直接抛出异常。</p>
<p>keepAliveTime设置为0L，表示空闲的线程会立刻终止。</p>
<p>workQueue则是使用LinkedBlockingQueue，但是没有设置范围，那么则是最大值（Integer.MAX_VALUE），这基本就相当于一个无界队列了。使用该“无界队列”则会带来哪些影响呢？当线程池中的线程数量等于corePoolSize 时，如果继续提交任务，该任务会被添加到阻塞队列workQueue中，当阻塞队列也满了之后，则线程池会新建线程执行任务直到maximumPoolSize。由于FixedThreadPool使用的是“无界队列”LinkedBlockingQueue，那么maximumPoolSize参数无效，同时指定的拒绝策略AbortPolicy也将无效。而且该线程池也不会拒绝提交的任务，如果客户端提交任务的速度快于任务的执行，那么keepAliveTime也是一个无效参数。</p>
<h3 id="SingleThreadExecutor"><a href="#SingleThreadExecutor" class="headerlink" title="SingleThreadExecutor"></a>SingleThreadExecutor</h3><p>SingleThreadExecutor是使用单个worker线程的Executor，即单线程工作模式。</p>
<p>作为单一worker线程的线程池，SingleThreadExecutor把corePool和maximumPoolSize均被设置为1，和FixedThreadPool一样使用的是无界队列LinkedBlockingQueue,所以带来的影响和FixedThreadPool一样。</p>
<h3 id="CachedThreadPool"><a href="#CachedThreadPool" class="headerlink" title="CachedThreadPool"></a>CachedThreadPool</h3><p>CachedThreadPool是一个会根据需要创建新线程的线程池 。</p>
<p>CachedThreadPool的corePool为0，maximumPoolSize为Integer.MAX_VALUE，这就意味着所有的任务一提交就会加入到阻塞队列中。keepAliveTime这是为60L，unit设置为TimeUnit.SECONDS，意味着空闲线程等待新任务的最长时间为60秒，空闲线程超过60秒后将会被终止。阻塞队列采用的SynchronousQueue，我们了解到SynchronousQueue是一个没有元素的阻塞队列(概念上的无界，其实是有界的)，加上corePool = 0 ，maximumPoolSize = Integer.MAX_VALUE，这样就会存在一个问题，如果主线程提交任务的速度远远大于CachedThreadPool的处理速度，则CachedThreadPool会不断地创建新线程来执行任务，这样有可能会导致系统耗尽CPU和内存资源，所以在<strong>使用该线程池是，一定要注意控制并发的任务数，否则创建大量的线程可能导致严重的性能问题</strong>。</p>
<h3 id="ScheduledThreadPool"><a href="#ScheduledThreadPool" class="headerlink" title="ScheduledThreadPool"></a>ScheduledThreadPool</h3><p>ScheduledThreadPool，创建一个可延迟调度的线程池。</p>
<p>ScheduledThreadPool的线程池处理类为ScheduledThreadPoolExecutor，通过构造我们可以得出corePool是可以自定义的，maximumPoolSize为Integer.MAX_VALUE，这就意味着所有的任务一提交就会加入到阻塞队列中。keepAliveTime为0，unit设置为TimeUnit.NANOSECONDS，意味着执行完延迟任务后会立马回收线程。阻塞队列采用DelayedWorkQueue(专为延迟队列而生),DelayedWorkQueue基于堆的数据结构，默认初始化容量为16。</p>
<p>我们知道Timer与TimerTask虽然可以实现线程的周期和延迟调度，但是Timer与TimerTask存在一些缺陷，所以对于这种定期、周期执行任务的调度策略，我们一般都是推荐ScheduledThreadPoolExecutor来实现。</p>
<p>具体分析请阅读大牛博文: </p>
<ul>
<li><a target="_blank" rel="noopener" href="http://cmsblogs.com/?p=2451">ScheduledThreadPoolExecutor详解一</a></li>
<li><a target="_blank" rel="noopener" href="https://www.cnblogs.com/sanzao/p/10760641.html">ScheduledThreadPoolExecutor详解二</a></li>
</ul>
<h3 id="WorkStealingPool"><a href="#WorkStealingPool" class="headerlink" title="WorkStealingPool"></a>WorkStealingPool</h3><p>WorkStealingPool是个特殊的线程池，但不长用，面试有时候可能会问到，内部实现原理其实是基于JDK1.7的ForkJoinPool框架，具体构造实现细节如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Creates a &#123;<span class="doctag">@code</span> ForkJoinPool&#125; with the given parameters.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> parallelism the parallelism level. For default value,</span></span><br><span class="line"><span class="comment"> * use &#123;<span class="doctag">@link</span> java.lang.Runtime#availableProcessors&#125;.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> factory the factory for creating new threads. For default value,</span></span><br><span class="line"><span class="comment"> * use &#123;<span class="doctag">@link</span> #defaultForkJoinWorkerThreadFactory&#125;.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> handler the handler for internal worker threads that</span></span><br><span class="line"><span class="comment"> * terminate due to unrecoverable errors encountered while executing</span></span><br><span class="line"><span class="comment"> * tasks. For default value, use &#123;<span class="doctag">@code</span> null&#125;.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> asyncMode if true,</span></span><br><span class="line"><span class="comment"> * establishes local first-in-first-out scheduling mode for forked</span></span><br><span class="line"><span class="comment"> * tasks that are never joined. This mode may be more appropriate</span></span><br><span class="line"><span class="comment"> * than default locally stack-based mode in applications in which</span></span><br><span class="line"><span class="comment"> * worker threads only process event-style asynchronous tasks.</span></span><br><span class="line"><span class="comment"> * For default value, use &#123;<span class="doctag">@code</span> false&#125;.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if parallelism less than or</span></span><br><span class="line"><span class="comment"> *         equal to zero, or greater than implementation limit</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> NullPointerException if the factory is null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> SecurityException if a security manager exists and</span></span><br><span class="line"><span class="comment"> *         the caller is not permitted to modify threads</span></span><br><span class="line"><span class="comment"> *         because it does not hold &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment"> *         java.lang.RuntimePermission&#125;&#123;<span class="doctag">@code</span> (&quot;modifyThread&quot;)&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">ForkJoinPool</span><span class="params">(<span class="type">int</span> parallelism,</span></span><br><span class="line"><span class="params">                    ForkJoinWorkerThreadFactory factory,</span></span><br><span class="line"><span class="params">                    UncaughtExceptionHandler handler,</span></span><br><span class="line"><span class="params">                    <span class="type">boolean</span> asyncMode)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>(checkParallelism(parallelism),</span><br><span class="line">         checkFactory(factory),</span><br><span class="line">         handler,</span><br><span class="line">         asyncMode ? FIFO_QUEUE : LIFO_QUEUE,</span><br><span class="line">         <span class="string">&quot;ForkJoinPool-&quot;</span> + nextPoolId() + <span class="string">&quot;-worker-&quot;</span>);</span><br><span class="line">    checkPermission();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>ForkJoinPool框架是个并行框架，在多核CPU中有着高效的性能体验。Java7 提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算，再把多个“小任务”的结果合并成总的计算结果。有关于ForkJoinPool知识，我们后续讲解。</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a target="_blank" rel="noopener" href="https://github.com/alibaba/p3c/blob/master/p3c-gitbook/SUMMARY.md">阿里巴巴Java开发手册</a></li>
<li><a target="_blank" rel="noopener" href="https://vipshop.github.io/vjtools/#/standard/">唯品会Java开发手册</a></li>
<li>《Java并发编程的艺术》</li>
</ul>
</section>
    <!-- Tags START -->
    
      <div class="tags">
        <span>Tags:</span>
        
  <a href="/tags#JVM及并发编程" >
    <span class="tag-code">JVM及并发编程</span>
  </a>

      </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2018/06/09/%E3%80%90Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E6%88%98%E3%80%91-%E6%B7%B1%E5%85%A5ThreadPoolExecutor%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6/">
        <span class="nav-arrow">← </span>
        
          【Java并发编程实战】-深入ThreadPoolExecutor工作机制
        
      </a>
    
    
      <a class="nav-right" href="/2018/06/10/Docker%E5%AE%89%E8%A3%85%E5%88%86%E5%B8%83%E5%BC%8F%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6-RabbitMQ/">
        
          Docker安装分布式消息中间件-RabbitMQ
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Utterances START -->
      <div id="utterances"></div>
      <script src="https://utteranc.es/client.js"
        repo="ltyeamin/blogtalks"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async></script>    
      <!-- Utterances END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="toc-nav-text">源码分析</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95"><span class="toc-nav-text">常用方法</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#FixedThreadPool"><span class="toc-nav-text">FixedThreadPool</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#SingleThreadExecutor"><span class="toc-nav-text">SingleThreadExecutor</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#CachedThreadPool"><span class="toc-nav-text">CachedThreadPool</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#ScheduledThreadPool"><span class="toc-nav-text">ScheduledThreadPool</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#WorkStealingPool"><span class="toc-nav-text">WorkStealingPool</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"><span class="toc-nav-text">参考资料</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://example.com/2018/06/10/【Java并发编程实战】线程池应用之Executors线程池静态工厂/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', '/css/images/error_icon.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== '/css/images/error_icon.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>






    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2024 | Proudly powered by <a href="https://hexo.io" target="_blank">Hexo</a>
    <br>
    Theme by <a target="_blank" rel="noopener" href="https://github.com/ltyeamin">tong.li</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("https://cdn.staticfile.org/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("https://cdn.staticfile.org/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      hljs.configure({useBR: true});
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->



<script src='https://cdn.staticfile.org/mermaid/8.11.2/mermaid.min.js'></script>



<script src="/js/script.js"></script>


  </body>
</html>